﻿namespace SharePoint.ImportExport.Core
{
    using System;
    using System.Collections;
    using System.Globalization;
    using System.IO;
    using System.Xml.Serialization;

    /// <summary>
    /// This is the main class for importing the list or library data. There has to be exactly one instance of this class for each items.xml file
    /// </summary>
    /// <remarks>
    /// Each items file can contain multiple profile instances
    /// </remarks>
    /// <example>
    /// <code>
    /// //Create a new instance of the list class
    /// SharePoint.ImportExport.Core.List list=new List();
    /// <para></para>
    /// //Add a new profile node (the profile node indicates to which list/library the data will be imported
    /// ItemType profile=new ItemType();
    /// list.ItemTypes.Add(profile);
    /// profile.Name="My Document Library";
    /// <para></para>
    /// Item item= new Item();
    /// profile.Items.Add(item);
    /// item.Displayname="My word document.doc";
    /// item.Filename="myworddoc.doc"; //This can also be an absolute or UNC path
    /// <para></para>
    /// Itemfield itemField= new Itemfield();
    /// itemField.Name="MyField";
    /// itemField.Type=FieldType.Text;
    /// itemField.Value="My data";
    /// item.Fields.Add(itemField);
    /// <para></para>
    /// //Create a new alert
    /// Alert alert= new Alert();
    /// alert.Frequency="Daily";
    /// alert.User="DOMAIN\\user";
    /// alert.Type="Modify";
    /// item.Alerts.Alert.Add(alert);
    /// <para></para>
    /// //Create a new portal listing
    /// Categories portalListings=new Categories();
    /// portalListings.Value="//Topics/strategy"; //This are will get the listing
    /// item.Categories.Add(portalListings);
    /// <para></para>
    /// try
    ///  {
    ///    list.Serialize("items.xml");
    ///  }
    /// catch(SPExportException ex)
    ///  {
    ///    Console.WriteLine("Exception occurred: "+ex.Message);
    ///   }
    /// </code>
    /// </example>
    [System.Xml.Serialization.XmlRootAttribute("list", Namespace = "", IsNullable = false)]
    public class ListOfItems
    {
        /// <summary>
        /// Internal collection of itemd
        /// </summary>
        private ContentTypeReferenceCollection listOfItems;

        /// <summary>
        /// Initializes a new instance of the ListOfItems class.
        /// </summary>
        /// <remarks>
        /// The constructor instantiates the ItemsOfContentType member</remarks>
        public ListOfItems()
        {
            this.listOfItems = new ContentTypeReferenceCollection();
        }

        /// <summary>
        /// Gets the collection of list items <see cref="SharePoint.ImportExport.Core.ContentTypeReferenceCollection"/>
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("profile", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public ContentTypeReferenceCollection ItemsOfContentType
        {
            get
            {
                return this.listOfItems;
            }
        }

        /// <summary>
        /// This is the serialization function for the items class
        /// </summary>
        /// <param name="fileName">this is the name of the XML file that will be generated</param>
        /// <returns>true if succeeded</returns>
        /// <remarks>The method will throw as SPExportException if the data is invalid</remarks>
        public bool Serialize(string fileName)
        {
            string dirName = fileName;
            int pos = dirName.LastIndexOf("\\");
            if (pos > 0)
            {
                dirName = dirName.Substring(0, pos);
            }

            if (pos != -1) 
            {
                if (!Directory.Exists(dirName))
                {
                    Directory.CreateDirectory(dirName);
                }
            }

            bool returnValue = true;
            if (this.ItemsOfContentType == null)
            {
                throw new SPExportException("The items.xml should contain at least one ItemType node");
            }

            foreach (ItemsOfContentType profile in this.ItemsOfContentType)
            {
                if (profile != null)
                {
                    try
                    {
                        this.ValidateItemType(profile);
                    }
                    catch (SPExportException ex)
                    {
                        throw ex;
                    }
                }
            }

            using (StreamWriter exportItemsFile = new StreamWriter(fileName, false))
            {
                try
                {
                    XmlSerializer mySerializer = new XmlSerializer(typeof(SharePoint.ImportExport.Core.ListOfItems));
                    mySerializer.Serialize(exportItemsFile, this);
                }
                catch (Exception serializationException)
                {
                    Console.WriteLine("Exception error: " + serializationException.Message);
                    SPExportException ex = new SPExportException(serializationException.Message);
                    throw ex;
                }
                finally
                {
                    exportItemsFile.Flush();
                    exportItemsFile.Close();
                }
            }

            return returnValue;
        }

        /// <summary>
        /// Validates the metadata property
        /// </summary>
        /// <param name="field">property to be validated</param>
        private void ValidateField(ItemProperty field)
        {
            if (field.Name == null)
            {
                throw new SPExportException("A field must have a name defined");
            }

            if (field.Value == null)
            {
                throw new SPExportException("A field must have the value defined");
            }
        }

        /// <summary>
        /// Validates the item
        /// </summary>
        /// <param name="item">Item to be validated</param>
        /// <remarks>Will call the ValidateField for each metadata property</remarks>
        private void ValidateItem(Item item)
        {
            if (item.Fields == null && item.DisplayName == null)
            {
                throw new SPExportException("A item node must have a either the field nodes or (displayname and filename defined)");
            }

            if (item.DisplayName == null && item.FileName != null)
            {
                throw new SPExportException("A item node must have both (displayname and filename defined)");
            }

            if (item.Fields != null)
            {
                int i = 0;
                foreach (ItemProperty field in item.Fields)
                {
                    if (field != null)
                    {
                        try
                        {
                            this.ValidateField(field);
                        }
                        catch (SPExportException ex)
                        {
                            throw new SPExportException("Field " + i.ToString(CultureInfo.InvariantCulture) + "validation failed. Error: " + ex.Message);
                        }

                        i++;
                    }
                }
            }
        }

        /// <summary>
        /// Validates a list of items
        /// </summary>
        /// <param name="itemType">list of items to be validated</param>
        private void ValidateItemType(ItemsOfContentType itemType)
        {
            if (itemType.Name == null)
            {
                throw new SPExportException("A ItemType node must have a name");
            }

            if (itemType.Items != null)
            {
                foreach (Item item in itemType.Items)
                {
                    if (item != null)
                    {
                        try
                        {
                            this.ValidateItem(item);
                        }
                        catch (SPExportException ex)
                        {
                            throw new SPExportException("Field validation in ItemType " + itemType.Name + "failed. Error: " + ex.Message);
                        }
                    }
                }
            }
        }
    }

    /// <summary>
    /// This is the class implementing the collection of Content Type References. This class contains  <see cref="SharePoint.ImportExport.Core.ItemsOfContentType"/> nodes
    /// </summary>
    /// <remarks>
    /// <seealso cref="SharePoint.ImportExport.Core.ItemsOfContentType"/><seealso cref="SharePoint.ImportExport.Core.List"/>
    /// </remarks>
    public class ContentTypeReferenceCollection : ICollection
    {
        /// <summary>
        /// Internal list of item types
        /// </summary>
        private ArrayList contentTypes;

        /// <summary>
        /// Initializes a new instance of the <see cref="ContentTypeReferenceCollection" /> class.
        /// </summary>
        /// <remarks>
        /// The constructor instantiates the profilesCollection member</remarks>
        public ContentTypeReferenceCollection()
        {
            this.contentTypes = new ArrayList();
        }
        #region ICollection Members

        /// <summary>
        /// Gets a value indicating whether access to the ArrayList is synchronized (thread-safe).
        /// </summary>
        /// <remarks>
        /// To guarantee the thread safety of the ArrayList, all operations must be done through the wrapper returned by the Synchronized method.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public bool IsSynchronized
        {
            get
            {
                return this.contentTypes.IsSynchronized;
            }
        }

        /// <summary>
        /// Gets value indicating the number of objects in the collection. Read-only.
        /// </summary>
        public int Count
        {
            get
            {
                return this.contentTypes.Count;
            }
        }

        /// <summary>
        /// Gets an object that can be used to synchronize access to the ArrayList.
        /// </summary>
        /// <remarks>
        /// To create a synchronized version of the ArrayList, use the Synchronized method. However, derived classes can provide their own synchronized version of the ArrayList using the SyncRoot property. The synchronizing code must perform operations on the SyncRoot of the ArrayList, not directly on the ArrayList. This ensures proper operation of collections that are derived from other objects. 
        /// Specifically, it maintains proper synchronization with other threads that might be simultaneously modifying the ArrayList object.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or 
        /// catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public object SyncRoot
        {
            get
            {
                return this.contentTypes.SyncRoot;
            }
        }

        #endregion

        /// <summary>
        /// Gets the element at the specified index.
        /// </summary>
        /// <param name="index">This is the index of the item</param>
        /// <returns>An object with a list of all items of a specific content type</returns>
        public ItemsOfContentType this[int index]
        {
            get 
            { 
                return (ItemsOfContentType)this.contentTypes[index]; 
            }
        }

        /// <summary>
        /// Copies the entire ItemType Array to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(ItemsOfContentType[] a, int index)
        {
            this.contentTypes.CopyTo(a, index);
        }

        /// <summary>
        /// Copies the entire ArrayList to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(Array a, int index)
        {
            this.contentTypes.CopyTo(a, index);
        }

        #region IEnumerable Members

        /// <summary>
        /// Returns an enumerator that can iterate through the ArrayList.
        /// </summary>
        /// <returns>The enumerator</returns>
        public IEnumerator GetEnumerator()
        {
            return this.contentTypes.GetEnumerator();
        }

        #endregion

        /// <summary>
        /// Adds an object to the end of the ArrayList.
        /// </summary>
        /// <param name="newItemType">New ItemType to be added to the list</param>
        public void Add(ItemsOfContentType newItemType)
        {
            this.contentTypes.Add(newItemType);
        }
    }

    /// <summary>
    /// Each profile instance represents a list or a library, the template for the list/library is identified by the Name attribute of the profile instance.
    /// </summary>
    /// <remarks>The profile contains a list of <see cref="SharePoint.ImportExport.Core.Item"/> items</remarks>
    /// <example>
    /// <code>
    /// //Create a new instance of the list class
    /// SharePoint.ImportExport.Core.List list=new List();
    /// <para></para>
    /// //Add a new profile node (the profile node indicates to which list/library the data will be imported
    /// ItemType profile=new ItemType();
    /// list.ItemTypes.Add(profile);
    /// profile.Name="My Document Library";
    /// <para></para>
    /// Item item= new Item();
    /// profile.Items.Add(item);
    /// item.Displayname="My word document.doc";
    /// item.Filename="myworddoc.doc"; //This can also be an absolute or UNC path
    /// <para></para>
    /// Itemfield itemField= new Itemfield();
    /// itemField.Name="MyField";
    /// itemField.Type=FieldType.Text;
    /// itemField.Value="My data";
    /// item.Fields.Add(itemField);
    /// <para></para>
    /// //Create a new alert
    /// Alert alert= new Alert();
    /// alert.Frequency="Daily";
    /// alert.User="DOMAIN\\user";
    /// alert.Type="Modify";
    /// item.Alerts.Alert.Add(alert);
    /// <para></para>
    /// //Create a new portal listing
    /// Categories portalListings=new Categories();
    /// portalListings.Value="//Topics/strategy"; //This are will get the listing
    /// item.Categories.Add(portalListings);
    /// <para></para>
    /// try
    ///  {
    ///    list.Serialize("items.xml");
    ///  }
    /// catch(SPExportException ex)
    ///  {
    ///   Console.WriteLine("Exception occurred: "+ex.Message);
    ///  }
    /// </code>
    /// </example>
    public class ItemsOfContentType
    {
        /// <summary>
        /// Internal collection of items
        /// </summary>
        private ItemsCollection items;

        /// <summary>
        /// The name member is used for identifying the list/library template.
        /// </summary>
        private string attributename;

        /// <summary>
        /// Boolean value that specifies whether the view is hidden.
        /// </summary>
        private bool hidden;

        /// <summary>
        /// Initializes a new instance of the <see cref="ItemsOfContentType" /> class
        /// </summary>
        /// <remarks>Instantiates the Item member</remarks>
        public ItemsOfContentType()
        {
            this.items = new ItemsCollection();
        }

        /// <summary>
        /// Gets the collection of items
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("item", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public ItemsCollection Items
        {
            get
            {
                return this.items;
            }
        }

        /// <summary>
        /// Gets or sets the name that used for identifying the list/library template.
        /// </summary>
        [System.Xml.Serialization.XmlAttributeAttribute()]
        public string Name
        {
            get
            {
                return this.attributename;
            }

            set
            {
                this.attributename = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the view is hidden.
        /// </summary>
        [System.Xml.Serialization.XmlAttributeAttribute("hidden", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public bool Hidden
        {
            get
            {
                return this.hidden;
            }

            set
            {
                this.hidden = value;
            }
        }
    }

    /// <summary>
    /// This is the class implementing the Items collection <see cref="SharePoint.ImportExport.Core.Item"/>
    /// </summary>
    /// <remarks>
    /// <seealso cref="SharePoint.ImportExport.Core.Item"/><seealso cref="SharePoint.ImportExport.Core.ItemsOfContentType"/>
    /// </remarks>
    public class ItemsCollection : ICollection
    {
        /// <summary>
        /// Internal collection of items
        /// </summary>
        private ArrayList itemsCollection;

        /// <summary>
        /// Initializes a new instance of the ItemsCollection class
        /// </summary>
        /// <remarks>
        /// Instantiates the itemsCollection member</remarks>
        public ItemsCollection()
        {
            this.itemsCollection = new ArrayList();
        }
        
        #region ICollection Members

        /// <summary>
        /// Gets a value indicating whether access to the ArrayList is synchronized (thread-safe).
        /// </summary>
        /// <remarks>
        /// To guarantee the thread safety of the ArrayList, all operations must be done through the wrapper returned by the Synchronized method.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public bool IsSynchronized
        {
            get
            {
                return this.itemsCollection.IsSynchronized;
            }
        }

        /// <summary>
        /// Gets value indicating the number of objects in the collection. Read-only.
        /// </summary>
        public int Count
        {
            get
            {
                return this.itemsCollection.Count;
            }
        }

        /// <summary>
        /// Gets an object that can be used to synchronize access to the ArrayList.
        /// </summary>
        /// <remarks>
        /// To create a synchronized version of the ArrayList, use the Synchronized method. However, derived classes can provide their own synchronized version of the ArrayList using the SyncRoot property. The synchronizing code must perform operations on the SyncRoot of the ArrayList, not directly on the ArrayList. This ensures proper operation of collections that are derived from other objects. 
        /// Specifically, it maintains proper synchronization with other threads that might be simultaneously modifying the ArrayList object.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or 
        /// catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public object SyncRoot
        {
            get
            {
                return this.itemsCollection.SyncRoot;
            }
        }

        #endregion

        /// <summary>
        /// Gets the element at the specified index.
        /// </summary>
        /// <param name="index">This is the index of the item</param>
        public Item this[int index]
        {
            get
            {
                return (Item)this.itemsCollection[index];
            }
        }

        #region IEnumerable Members

        /// <summary>
        /// Returns an enumerator that can iterate through the ArrayList.
        /// </summary>
        /// <returns>The enumerator</returns>
        public IEnumerator GetEnumerator()
        {
            return this.itemsCollection.GetEnumerator();
        }

        #endregion

        /// <summary>
        /// Copies the entire Item array to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(Item[] a, int index)
        {
            this.itemsCollection.CopyTo(a, index);
        }

        /// <summary>
        /// Copies the entire ArrayList to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(Array a, int index)
        {
            this.itemsCollection.CopyTo(a, index);
        }

        /// <summary>
        /// Adds an object to the end of the ArrayList.
        /// </summary>
        /// <param name="newItem">New Item to be added to the list</param>
        public void Add(Item newItem)
        {
            this.itemsCollection.Add(newItem);
        }
    }

    /// <summary>
    /// This class encapsulates a list item or a document in the document library. This is a member of <see cref="SharePoint.ImportExport.Core.ItemsOfContentType"/>
    /// </summary>
    /// <remarks>
    /// <seealso cref="SharePoint.ImportExport.Core.ItemsOfContentType"/>
    /// </remarks>
    /// <example>
    /// <code>
    /// //Create a ItemType
    /// Item item= new Item();
    /// item.Displayname="My word document.doc";
    /// item.Filename="myworddoc.doc"; //This can also be an absolute or UNC path
    /// <para></para>
    /// Itemfield itemField= new Itemfield();
    /// itemField.Name="MyField";
    /// itemField.Type=FieldType.Text;
    /// itemField.Value="My data";
    /// item.Fields.Add(itemField);
    /// <para></para>
    /// itemField= new Itemfield("MyUrlField",FieldType.UUL,"http://www.microsoft.com, Microsoft"); //remember the space before the comma
    /// item.Fields.Add(itemField);
    /// <para></para>
    /// profile.Items.Add(item);
    /// <para></para>
    /// </code>
    /// </example>
    public class Item
    {
        /// <summary>
        /// This is the displayname of the file
        /// </summary>
        private string displayname;

        /// <summary>
        /// Tis is the filename of the file in the filesystem
        /// </summary>
        private string filename;

        /// <summary>
        /// This is the security node
        /// </summary>
        private UserInfo security;

        /// <summary>
        /// This is the name of the person for the audit history
        /// </summary>
        private string owner;

        /// <summary>
        /// This is the description of the item
        /// </summary>
        private string description;

        /// <summary>
        /// This is the comment of the item
        /// </summary>
        private string comment;

        /// <summary>
        /// This is the version info of the item
        /// </summary>
        private string version;

        /// <summary>
        /// This is the collection of all the metadata associated to the item
        /// </summary>
        private ItemsFieldsCollection fields;

        /// <summary>
        /// This is the list item ID
        /// </summary>
        private int id = 0;

        /// <summary>
        /// This is the collection of versions (if any)
        /// </summary>
        private VersionsCollection versions;
        
        /// <summary>
        /// This is the collection of alerts (if any)
        /// </summary>
        private AlertsCollection alerts;

        /// <summary>
        /// This is the collection of attachments (if any)
        /// </summary>
        private AttachmentsCollection attachments;
        
        /// <summary>
        /// This is the collection of categories (if any)
        /// </summary>
        private CategoriesCollection categories;

        /// <summary>
        /// Initializes a new instance of the Item class
        /// </summary>
        /// <remarks>Initializes also the internal data structures</remarks>
        public Item()
        {
            this.fields = new ItemsFieldsCollection();
            this.alerts = new AlertsCollection();
            this.categories = new CategoriesCollection();
            this.attachments = new AttachmentsCollection();
            this.versions = new VersionsCollection();
        }

        /// <summary>
        /// Gets or sets the displayname of the Attachment
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("displayname", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string DisplayName
        {
            get
            {
                return this.displayname;
            }

            set
            {
                this.displayname = Miscallaneous.FixName(value);
            }
        }

        /// <summary>
        /// Gets or sets filename of the Attachment
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("filename", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string FileName
        {
            get
            {
                return this.filename;
            }

            set
            {
                this.filename = value;
            }
        }

        /// <summary>
        /// Gets or sets the name of the person who performed the versioning. Used for auditing purposes
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("owner", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Owner
        {
            get
            {
                return this.owner;
            }

            set
            {
                this.owner = value;
            }
        }

        /// <summary>
        /// Gets or sets the description of the file
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("description", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Description
        {
            get
            {
                return this.description;
            }

            set
            {
                this.description = value;
            }
        }

        /// <summary>
        /// Gets or sets the comment for the audit history
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("comment", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Comment
        {
            get
            {
                return this.comment;
            }

            set
            {
                this.comment = value;
            }
        }

        /// <summary>
        /// Gets or sets the version information of the document
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("version", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Version
        {
            get
            {
                return this.version;
            }

            set
            {
                this.version = value;
            }
        }

        /// <summary>
        /// Gets the collection of properties associated to the item
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("field", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public ItemsFieldsCollection Fields
        {
            get
            {
                return this.fields;
            }
        }

        /// <summary>
        /// Gets the collection of attachments. Only valid for lists
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("attachment", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public AttachmentsCollection Attachments
        {
            get
            {
                return this.attachments;
            }
        }

        /// <summary>
        /// Gets the list of the portal areas that will get portal listings to the item
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("categories", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public CategoriesCollection Categories
        {
            get
            {
                return this.categories;
            }
        }

        /// <summary>
        /// Gets the list of alerts that will be created
        /// </summary>
        [System.Xml.Serialization.XmlArray("alerts", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        [System.Xml.Serialization.XmlArrayItem("alert", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public AlertsCollection Alerts
        {
            get
            {
                return this.alerts;
            }
        }

        /// <summary>
        /// Gets the list of the versions that will be created. See <see cref="SharePoint.ImportExport.Core.VersionsCollection"/>
        /// </summary>
        /// <example>
        /// <code>
        /// Item itemV= new Item();
        /// item.Versions.Add(itemV);
        /// itemV.Owner="Kimmo Forss";
        /// itemV.Displayname="My word document.doc";
        /// itemV.Filename="myworddoc2.doc"; //This can also be an absolute or UNC path
        /// </code>
        /// </example>
        [System.Xml.Serialization.XmlArray("versions", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        [System.Xml.Serialization.XmlArrayItem("item", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public VersionsCollection Versions
        {
            get
            {
                return this.versions;
            }
        }

        /// <summary>
        /// Gets or sets the ID of the listitem
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("id", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public int ID
        {
            get
            {
                return this.id;
            }

            set
            {
                this.id = value;
            }
        }

        /// <summary>
        /// Gets or sets the security information that will be applied to the item
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("security", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public UserInfo UserInfo
        {
            get
            {
                return this.security;
            }
    
            set
            {
                this.security = value;
            }
        }
    }

    /// <summary>
    /// This is the class implementing the ItemFields collection <see cref="SharePoint.ImportExport.Core.ItemProperty"/>
    /// </summary>
    /// <seealso cref="SharePoint.ImportExport.Core.ItemProperty"/><seealso cref="SharePoint.ImportExport.Core.Item"/>
    public class ItemsFieldsCollection : ICollection
    {
        /// <summary>
        /// This is the collection of fields
        /// </summary>
        private ArrayList itemsFieldsCollection;

        /// <summary>
        /// Initializes a new instance of the ItemsFieldsCollection class
        /// </summary>
        /// <remarks>Instantiates the itemsFieldsCollection member</remarks>
        public ItemsFieldsCollection()
        {
            this.itemsFieldsCollection = new ArrayList();
        }

        #region ICollection Members

        /// <summary>
        /// Gets a value indicating whether access to the ArrayList is synchronized (thread-safe).
        /// </summary>
        /// <remarks>
        /// To guarantee the thread safety of the ArrayList, all operations must be done through the wrapper returned by the Synchronized method.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public bool IsSynchronized
        {
            get
            {
                return this.itemsFieldsCollection.IsSynchronized;
            }
        }

        /// <summary>
        /// Gets value indicating the number of objects in the collection. Read-only.
        /// </summary>
        public int Count
        {
            get
            {
                return this.itemsFieldsCollection.Count;
            }
        }

        /// <summary>
        /// Gets an object that can be used to synchronize access to the ArrayList.
        /// </summary>
        /// <remarks>
        /// To create a synchronized version of the ArrayList, use the Synchronized method. However, derived classes can provide their own synchronized version of the ArrayList using the SyncRoot property. The synchronizing code must perform operations on the SyncRoot of the ArrayList, not directly on the ArrayList. This ensures proper operation of collections that are derived from other objects. 
        /// Specifically, it maintains proper synchronization with other threads that might be simultaneously modifying the ArrayList object.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or 
        /// catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public object SyncRoot
        {
            get
            {
                return this.itemsFieldsCollection.SyncRoot;
            }
        }

        #endregion

        /// <summary>
        /// Gets the element at the specified index.
        /// </summary>
        /// <param name="index">This is the index of the item</param>
        public ItemProperty this[int index]
        {
            get 
            { 
                return (ItemProperty)this.itemsFieldsCollection[index]; 
            }
        }

        #region IEnumerable Members

        /// <summary>
        /// Returns an enumerator that can iterate through the ArrayList.
        /// </summary>
        /// <returns>The enumerator</returns>
        public IEnumerator GetEnumerator()
        {
            return this.itemsFieldsCollection.GetEnumerator();
        }

        #endregion

        /// <summary>
        /// Copies the entire ItemField Array to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(ItemProperty[] a, int index)
        {
            this.itemsFieldsCollection.CopyTo(a, index);
        }

        /// <summary>
        /// Copies the entire ArrayList to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(Array a, int index)
        {
            this.itemsFieldsCollection.CopyTo(a, index);
        }

        /// <summary>
        /// Adds an object to the end of the ArrayList.
        /// </summary>
        /// <param name="newItemField">New ItemField to be added to the list</param>
        public void Add(ItemProperty newItemField)
        {
            this.itemsFieldsCollection.Add(newItemField);
        }
    }

    /// <summary>
    /// This is the class encapsulating the meta data 
    /// </summary>
    public class ItemProperty
    {
        /// <summary>
        /// This is the name of the metadata field
        /// </summary>
        private string name;

        /// <summary>
        /// This is the field type
        /// </summary>
        private FieldType type;

        /// <summary>
        /// This is the actual field value
        /// </summary>
        private string fieldvalue;

        /// <summary>
        /// Initializes a new instance of the ItemProperty class
        /// </summary>
        public ItemProperty()
        {
        }

        /// <summary>
        /// Initializes a new instance of the ItemProperty class with parameters
        /// </summary>
        /// <param name="fieldName">Name of the field</param>
        /// <param name="fieldType">Datatype of the field</param>
        /// <param name="fieldValue">Value of the field</param>
        public ItemProperty(string fieldName, FieldType fieldType, string fieldValue)
        {
            this.name = fieldName;
            this.type = fieldType;
            this.fieldvalue = fieldValue;
        }
        
        /// <summary>
        /// Gets or sets the name of the metadata field
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("name", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Name
        {
            get
            {
                return this.name;
            }

            set
            {
                this.name = value;
            }
        }

        /// <summary>
        /// Gets or sets the datatype of the metadata field
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("type", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public FieldType DataType
        {
            get
            {
                return this.type;
            }

            set
            {
                this.type = value;
            }
        }

        /// <summary>
        /// Gets or sets the value of the metadata field
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("value", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Value
        {
            get
            {
                return this.fieldvalue;
            }

            set
            {
                this.fieldvalue = value;
            }
        }
    }

    /// <summary>
    /// This is the class implementing the Categories collection
    /// </summary>
    public class CategoriesCollection : ICollection
    {
        /// <summary>
        /// This is the collection of categories
        /// </summary>
        private ArrayList categories;

        /// <summary>
        /// Initializes a new instance of the CategoriesCollection class
        /// </summary>
        /// <remarks>Instantiates the categories member</remarks>
        public CategoriesCollection()
        {
            this.categories = new ArrayList();
        }
        
        #region ICollection Members

        /// <summary>
        /// Gets a value indicating whether access to the ArrayList is synchronized (thread-safe).
        /// </summary>
        /// <remarks>
        /// To guarantee the thread safety of the ArrayList, all operations must be done through the wrapper returned by the Synchronized method.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public bool IsSynchronized
        {
            get
            {
                return this.categories.IsSynchronized;
            }
        }

        /// <summary>
        /// Gets value indicating the number of objects in the collection. Read-only.
        /// </summary>
        public int Count
        {
            get
            {
                return this.categories.Count;
            }
        }

        /// <summary>
        /// Gets an object that can be used to synchronize access to the ArrayList.
        /// </summary>
        /// <remarks>
        /// To create a synchronized version of the ArrayList, use the Synchronized method. However, derived classes can provide their own synchronized version of the ArrayList using the SyncRoot property. The synchronizing code must perform operations on the SyncRoot of the ArrayList, not directly on the ArrayList. This ensures proper operation of collections that are derived from other objects. 
        /// Specifically, it maintains proper synchronization with other threads that might be simultaneously modifying the ArrayList object.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or 
        /// catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public object SyncRoot
        {
            get
            {
                return this.categories.SyncRoot;
            }
        }

        #endregion

        /// <summary>
        /// Gets the element at the specified index.
        /// </summary>
        /// <param name="index">This is the index of the item</param>
        public Category this[int index]
        {
            get 
            {
                return (Category)this.categories[index];
            }
        }

        #region IEnumerable Members

        /// <summary>
        /// Returns an enumerator that can iterate through the ArrayList.
        /// </summary>
        /// <returns>The enumerator</returns>
        public IEnumerator GetEnumerator()
        {
            return this.categories.GetEnumerator();
        }

        #endregion

        /// <summary>
        /// Copies the entire Category Array to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(Category[] a, int index)
        {
            this.categories.CopyTo(a, index);
        }

        /// <summary>
        /// Copies the entire ArrayList to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(Array a, int index)
        {
            this.categories.CopyTo(a, index);
        }

        /// <summary>
        /// Adds an object to the end of the ArrayList.
        /// </summary>
        /// <param name="newCategory">New Categories to be added to the list</param>
        public void Add(Category newCategory)
        {
            this.categories.Add(newCategory);
        }
    }

    /// <summary>
    /// This class encapsulates all the portal listings that will be created
    /// </summary>
    /// <example>
    /// <code>
    /// //Create a new portal listing
    /// Categories portalListings=new Categories();
    /// portalListings.Value="//Topics/strategy";
    /// item.Categories.Add(portalListings);
    /// </code></example>
    public class Category
    {
       /// <summary>
        /// This is the relative Url to the topic area that will get the listing
        /// </summary>
        /// <example>Topics/Divisions</example>
        private string categoryValue;

        /// <summary>
        /// Initializes a new instance of the Category class
        /// </summary>
        public Category()
        {
        }

        /// <summary>
        /// Initializes a new instance of the Category class specifying value as a parameter
        /// </summary>
        /// <param name="category">This is the relative Url to the topic area that will get the listing</param>
        public Category(string category)
        {
            this.categoryValue = category;
        }

        /// <summary>
        /// Gets or sets the relative Url to the topic area that will get the listing
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("value", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string Value
        {
            get
            {
                return this.categoryValue;
            }

            set
            {
                this.categoryValue = value;
            }
        }
    }

    /// <summary>
    /// This is the class implementing the ItemFields collection <see cref="SharePoint.ImportExport.Core.ItemProperty"/>
    /// </summary>
    /// <seealso cref="SharePoint.ImportExport.Core.Attachment"/><seealso cref="SharePoint.ImportExport.Core.Item"/>
    public class AttachmentsCollection : ICollection
    {
        /// <summary>
        /// This is the internal list of attachments
        /// </summary>
        private ArrayList attachmentsCollection;
        
        /// <summary>
        /// Initializes a new instance of the AttachmentsCollection class
        /// </summary>
        /// <remarks>Instantiates the itemsFieldsCollection member</remarks>
        public AttachmentsCollection()
        {
            this.attachmentsCollection = new ArrayList();
        }

        #region ICollection Members

        /// <summary>
        /// Gets a value indicating whether access to the ArrayList is synchronized (thread-safe).
        /// </summary>
        /// <remarks>
        /// To guarantee the thread safety of the ArrayList, all operations must be done through the wrapper returned by the Synchronized method.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public bool IsSynchronized
        {
            get
            {
                return this.attachmentsCollection.IsSynchronized;
            }
        }

        /// <summary>
        /// Gets value indicating the number of objects in the collection. Read-only.
        /// </summary>
        public int Count
        {
            get
            {
                return this.attachmentsCollection.Count;
            }
        }

        /// <summary>
        /// Gets an object that can be used to synchronize access to the ArrayList.
        /// </summary>
        /// <remarks>
        /// To create a synchronized version of the ArrayList, use the Synchronized method. However, derived classes can provide their own synchronized version of the ArrayList using the SyncRoot property. The synchronizing code must perform operations on the SyncRoot of the ArrayList, not directly on the ArrayList. This ensures proper operation of collections that are derived from other objects. 
        /// Specifically, it maintains proper synchronization with other threads that might be simultaneously modifying the ArrayList object.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or 
        /// catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public object SyncRoot
        {
            get
            {
                return this.attachmentsCollection.SyncRoot;
            }
        }

        #endregion

        /// <summary>
        /// Gets the element at the specified index.
        /// </summary>
        /// <param name="index">This is the index of the item</param>
        public Attachment this[int index]
        {
            get 
            {
                return (Attachment)this.attachmentsCollection[index]; 
            }
        }

        #region IEnumerable Members

        /// <summary>
        /// Returns an enumerator that can iterate through the ArrayList.
        /// </summary>
        /// <returns>The enumerator</returns>
        public IEnumerator GetEnumerator()
        {
            return this.attachmentsCollection.GetEnumerator();
        }

        #endregion

        /// <summary>
        /// Copies the entire Attachment Array to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(Attachment[] a, int index)
        {
            this.attachmentsCollection.CopyTo(a, index);
        }

        /// <summary>
        /// Copies the entire ArrayList to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(Array a, int index)
        {
            this.attachmentsCollection.CopyTo(a, index);
        }

        /// <summary>
        /// Adds an object to the end of the ArrayList.
        /// </summary>
        /// <param name="newAttachment">New Attachment to be added to the list</param>
        public void Add(Attachment newAttachment)
        {
            this.attachmentsCollection.Add(newAttachment);
        }
    }

    /// <summary>
    /// This is the class encapsulating the attachment
    /// </summary>
    /// <example>
    /// <code>
    /// Attachment attachment=new Attachment();
    /// attachment.DisplayName="Invitation.doc";
    /// attachment.FileName="Invitation.doc";
    /// item.Attachments.Add(attachment);
    /// </code>
    /// </example>
    /// <remarks><seealso cref="SharePoint.ImportExport.Core.List"/> and <seealso cref="SharePoint.ImportExport.Core.Item"/></remarks>
    public class Attachment
    {
        /// <summary>
        /// This is the displayname of the attachment
        /// </summary>
        private string displayname;

        /// <summary>
        /// This is the filename of the file in the filesystem
        /// </summary>
        private string filename;

        /// <summary>
        /// Initializes a new instance of the Attachment class
        /// </summary>
        public Attachment()
        {
        }

        /// <summary>
        /// Initializes a new instance of the Attachment class specifying the attachment info
        /// </summary>
        /// <param name="displayName">This is the display name of the attachment</param>
        /// <param name="fileName">This is the filename of the attachment</param>
        public Attachment(string displayName, string fileName)
        {
            this.displayname = displayName;
            this.filename = fileName;
        }

        /// <summary>
        /// Gets or sets a value the displayname of the Attachment
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("displayname", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string DisplayName
        {
            get
            {
                return this.displayname;
            }

            set
            {
                this.displayname = Miscallaneous.FixName(value);
            }
        }

        /// <summary>
        /// Gets or sets the filename of the Attachment
        /// </summary>
        [System.Xml.Serialization.XmlElementAttribute("filename", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string FileName
        {
            get
            {
                return this.filename;
            }

            set
            {
                this.filename = value;
            }
        }
    }

    /// <summary>
    /// This is the class implementing the Versions collection
    /// </summary>
    /// <remarks>This class is used to add version of existing files. Note that the filename for each item added here must be the same that this item has
    /// <example>
    /// <code>
    /// Create the first item before adding versions
    /// Item versionItem= new Item();
    /// item.Versions.Add(versionItem);
    /// versionItem.Displayname="My word document.doc"; //Must be the same as item.DisplayName
    /// versionItem.Filename="myworddoc2.doc"; //This can also be an absolute or UNC path
    /// versionItem.Owner="Joe User";
    /// versionItem.Comment="Audit history comments";
    /// </code>
    /// </example>
    /// </remarks>
    public class VersionsCollection : ICollection
    {
        /// <summary>
        /// This is the internal list of versions
        /// </summary>
        private ArrayList versionsCollection;

        /// <summary>
        /// Initializes a new instance of the VersionsCollection class
        /// </summary>
        /// <remarks>Instantiates the categories member</remarks>
        public VersionsCollection()
        {
            this.versionsCollection = new ArrayList();
        }
        
        #region ICollection Members

        /// <summary>
        /// Gets a value indicating whether access to the ArrayList is synchronized (thread-safe).
        /// </summary>
        /// <remarks>
        /// To guarantee the thread safety of the ArrayList, all operations must be done through the wrapper returned by the Synchronized method.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public bool IsSynchronized
        {
            get
            {
                return this.versionsCollection.IsSynchronized;
            }
        }

        /// <summary>
        /// Gets value indicating the number of objects in the collection. Read-only.
        /// </summary>
        public int Count
        {
            get
            {
                return this.versionsCollection.Count;
            }
        }

        /// <summary>
        /// Gets an object that can be used to synchronize access to the ArrayList.
        /// </summary>
        /// <remarks>
        /// To create a synchronized version of the ArrayList, use the Synchronized method. However, derived classes can provide their own synchronized version of the ArrayList using the SyncRoot property. The synchronizing code must perform operations on the SyncRoot of the ArrayList, not directly on the ArrayList. This ensures proper operation of collections that are derived from other objects. 
        /// Specifically, it maintains proper synchronization with other threads that might be simultaneously modifying the ArrayList object.
        /// Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads could still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or 
        /// catch the exceptions resulting from changes made by other threads.
        /// </remarks>
        public object SyncRoot
        {
            get
            {
                return this.versionsCollection.SyncRoot;
            }
        }

        #endregion

        /// <summary>
        /// Gets the element at the specified index.
        /// </summary>
        /// <param name="index">This is the index of the item</param>
        public Item this[int index]
        {
            get 
            {
                return (Item)this.versionsCollection[index];
            }
        }

        #region IEnumerable Members

        /// <summary>
        /// Returns an enumerator that can iterate through the ArrayList.
        /// </summary>
        /// <returns>The enumerator</returns>
        public IEnumerator GetEnumerator()
        {
            return this.versionsCollection.GetEnumerator();
        }

        #endregion

        /// <summary>
        /// Copies the entire Version Array to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(Item[] a, int index)
        {
            this.versionsCollection.CopyTo(a, index);
        }

        /// <summary>
        /// Copies the entire ArrayList to a compatible one-dimensional Array, starting at the specified index of the target array.
        /// </summary>
        /// <param name="a">The one-dimensional Array that is the destination of the elements copied from ArrayList. The Array must have zero-based indexing. </param>
        /// <param name="index">The zero-based index in array at which copying begins</param>
        public void CopyTo(Array a, int index)
        {
            this.versionsCollection.CopyTo(a, index);
        }

        /// <summary>
        /// Adds an object to the end of the ArrayList.
        /// </summary>
        /// <param name="newItem">New Item to be added to the list</param>
        public void Add(Item newItem)
        {
            this.versionsCollection.Add(newItem);
        }
    }
}
